home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / exampleCode / opengl / extensions / samples / surfgrid.c < prev    next >
C/C++ Source or Header  |  1996-11-11  |  22KB  |  697 lines

  1. /*
  2.  * Copyright (c) 1994 Silicon Graphics, Inc.
  3.  * 
  4.  * Permission to use, copy, modify, distribute, and sell this software and
  5.  * its documentation for any purpose is hereby granted without fee,
  6.  * provided that (i) the above copyright notices and this permission
  7.  * notice appear in all copies of the software and related documentation,
  8.  * and (ii) the name of Silicon Graphics may not be used in any
  9.  * advertising or publicity relating to the software without the specific,
  10.  * prior written permission of Silicon Graphics.
  11.  * 
  12.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
  13.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
  14.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  15.  * 
  16.  * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL,
  17.  * INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
  18.  * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  19.  * OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
  20.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  21.  * OF THIS SOFTWARE.
  22.  */
  23. /*
  24.  * surfgrid.c - demonstration of polygon_offset extension
  25.  *
  26.  * 1994 Simon Hui - Silicon Graphics Computer Systems
  27.  *
  28.  *  $Revision: 1.1 $
  29.  *
  30.  * usage:
  31.  *    surfgrid [-f (full screen)] [-h(elp)]
  32.  *
  33.  * The program displays a torus made of bezier patches.  The outline of the
  34.  * patches is displayed as lines drawn on the surface.  polygon_offset is used to
  35.  * displace the depth of the patches so it does not interfere with the lines.
  36.  *
  37.  * keys:
  38.  *    p    toggle polygon offset
  39.  *    m    toggle multisampling
  40.  *      s       toggle surface drawing
  41.  *    g    toggle grid drawing
  42.  *    f    toggle smooth/flat shading
  43.  *    n    toggle whether to use GL evaluators or GLU nurbs
  44.  *    u    decr number of segments in U direction
  45.  *    U    incr number of segments in U direction
  46.  *    v    decr number of segments in V direction
  47.  *    V    incr number of segments in V direction
  48.  *    h    help
  49.  *    escape    quit
  50.  *
  51.  */
  52. #include <stdlib.h>
  53. #include <stdio.h>
  54. #include <string.h>
  55. #include <math.h>
  56. #include <GL/glu.h>
  57. #include <GL/glx.h>
  58. #include <X11/keysym.h>
  59. #include <Xm/MwmUtil.h>
  60. #include "util.h"
  61.  
  62. #define W 600
  63. #define H 600
  64.  
  65. static long winwidth = W, winheight = H;
  66. GC xgc;
  67. Display *dpy;
  68. Colormap cmap;
  69. Window window;
  70. XVisualInfo *vi;
  71. GLXContext cx;
  72. GLUnurbsObj *nobj;
  73. GLuint surflist, gridlist;
  74.  
  75. int useglunurbs = 0;
  76. int smooth = 1;
  77. int tracking = 0;
  78. int showgrid = 1;
  79. int showsurf = 1;
  80. GLboolean hasMultisampling;
  81. float modelmatrix[16] = {
  82.     1, 0, 0, 0,
  83.     0, 1, 0, 0,
  84.     0, 0, 1, 0,
  85.     0, 0, 0, 1,
  86. };
  87.  
  88. float scale = 0.5;
  89. float bias = 0.002;
  90. int usegments=4;
  91. int vsegments=4;
  92.  
  93. int spindx, spindy;
  94. int startx, starty;
  95. int curx, cury;
  96.  
  97. void redraw(void);
  98. void createlists(void);
  99. Window createwindow(int argc, char **argv, Bool fullscreen);
  100.  
  101. float torusnurbpts[], torusbezierpts[];
  102.  
  103. void eventloop( void )
  104. {
  105.     XEvent event;
  106.     XButtonEvent *bev;
  107.     int x, y, size;
  108.     unsigned int w, h, bw, depth;
  109.     Window root;
  110.     
  111.     for (;;) {
  112.     if (XPending(dpy)) {
  113.         XNextEvent(dpy, &event);
  114.         bev = (XButtonEvent *) &event;
  115.         switch (event.type) {
  116.           case KeyPress:
  117.         {
  118.             char buf[100];
  119.             int rv;
  120.             KeySym ks;
  121.  
  122.             rv = XLookupString(&event.xkey, buf, sizeof(buf), &ks, 0);
  123.             switch (ks) {
  124.               case XK_n:
  125.             useglunurbs = !useglunurbs;
  126.             break;
  127. #ifdef GL_EXT_polygon_offset
  128.                       case XK_p:
  129.                         if (glIsEnabled( GL_POLYGON_OFFSET_EXT )) {
  130.                 glDisable( GL_POLYGON_OFFSET_EXT );
  131.                 printf("disabling polygon offset\n");
  132.             } else {
  133.                 glEnable( GL_POLYGON_OFFSET_EXT );
  134.                 printf("enabling polygon offset\n");
  135.             }
  136.             break;
  137. #endif
  138. #ifdef GL_SGIS_multisample
  139.               case XK_m:
  140.             if (hasMultisampling) {
  141.                 if (glIsEnabled( GL_MULTISAMPLE_SGIS )) {
  142.                 glDisable( GL_MULTISAMPLE_SGIS );
  143.                                 printf("Multisampling off\n");
  144.                 } else {
  145.                 glEnable( GL_MULTISAMPLE_SGIS );
  146.                                 printf("Multisampling on\n");
  147.                 }
  148.             }
  149.             break;
  150. #endif
  151.               case XK_g:
  152.                 showgrid = !showgrid;
  153.                     break;
  154.               case XK_t:
  155.                         showsurf = !showsurf;
  156.             break;
  157.               case XK_f:
  158.             smooth = !smooth;
  159.             if (smooth) {
  160.                 glShadeModel( GL_SMOOTH );
  161.             } else {
  162.                 glShadeModel( GL_FLAT );
  163.             }
  164.             break;
  165.               case XK_S:
  166.             scale += 0.1;
  167.             printf( "scale: %g\n", scale);
  168.             break;
  169.               case XK_s:
  170.             scale -= 0.1;
  171.             printf( "scale: %g\n", scale);
  172.             break;
  173.               case XK_B:
  174.             bias += 0.0001;
  175.             printf( "bias:  %g\n", bias);
  176.             break;
  177.               case XK_b:
  178.             bias -= 0.0001;
  179.             printf( "bias:  %g\n", bias);
  180.             break;
  181.               case XK_u:
  182.                         if (usegments > 1)
  183.                             usegments--;
  184.             createlists();
  185.             break;
  186.               case XK_U:
  187.             usegments++;
  188.             createlists();
  189.             break;
  190.               case XK_v:
  191.                         if (vsegments > 1)
  192.                             vsegments--;
  193.             createlists();
  194.             break;
  195.               case XK_V:
  196.             vsegments++;
  197.             createlists();
  198.             break;
  199.                       case XK_h:
  200.                       case XK_question:
  201.                         printf("Keys:\tp - toggle polygon offset\n");
  202.                         printf("\tb/B -    decr/incr polygon offset bias\n");
  203.                         printf("\ts/S -    decr/incr polygon offset scale\n");
  204.                         printf("\tm - toggle multisampling\n");
  205.                         printf("\tt - toggle surface drawing\n");
  206.                         printf("\tg - toggle grid drawing\n");
  207.                         printf("\tf - toggle smooth/flat shading\n");
  208.                         printf("\tn - toggle between GL evaluators\
  209.  and GLU nurbs\n");
  210.                         printf("\tu/U - decr/incr number of segments\
  211.  in U direction\n");
  212.                         printf("\tv/V -    decr/incr number of segments\
  213.  in V direction\n");
  214.                         printf("\th/? - help\n");
  215.                         printf("\tEsc - quit\n");
  216.                         printf("To move the object press a mouse button\
  217.  and move the mouse\n");
  218.             break;
  219.               case XK_Escape:
  220.             exit(EXIT_SUCCESS);
  221.             break;
  222.             }
  223.             if (!XPending(dpy)) redraw();
  224.         }
  225.         break;
  226.           case Expose:
  227.         XGetGeometry(dpy, window, &root, &x, &y, &w, &h, &bw, &depth);
  228.         winwidth = w;
  229.         winheight = h;
  230.         size = (winwidth < winheight ? winwidth : winheight);
  231.         glViewport((winwidth-size)/2, (winheight-size)/2, size, size);
  232.         redraw();
  233.         break;
  234.           case ConfigureNotify:
  235.         winwidth = event.xconfigure.width;
  236.         winheight = event.xconfigure.height;
  237.         size = (winwidth < winheight ? winwidth : winheight);
  238.         glViewport((winwidth-size)/2, (winheight-size)/2, size, size);
  239.         redraw();
  240.         break;
  241.           case ButtonPress:
  242.         curx = startx = bev->x;
  243.         cury = starty = bev->y;
  244.         spindx = 0;
  245.         spindy = 0;
  246.         tracking = True;
  247.         break;
  248.           case ButtonRelease:
  249.         /*
  250.          * If user released the button while moving the mouse, keep
  251.          * spinning.
  252.          */
  253.         if (bev->x != curx || bev->y != cury) {
  254.             spindx = bev->x - curx;
  255.             spindy = bev->y - cury;
  256.         }
  257.         tracking = False;
  258.         break;
  259.           case MotionNotify:
  260.         if (XPending(dpy))
  261.                     break;
  262.         curx = bev->x;
  263.         cury = bev->y;
  264.         if (curx != startx || cury != starty) {
  265.             redraw();
  266.             startx = curx;
  267.             starty = cury;
  268.         }
  269.         break;
  270.         }
  271.     } else {
  272.         if (!tracking && (spindx!=0 || spindy!=0)) {
  273.         redraw();
  274.         }
  275.     }
  276.     }
  277. }
  278.  
  279. void gridmaterials(void)
  280. {
  281.     float front_mat_diffuse[] = { 0, 0, 0, 0 };
  282.     float front_mat_ambient[] = { 0, 0, 0, 0 };
  283.     float back_mat_diffuse[] = { 0, 0, 0, 0 };
  284.     float back_mat_ambient[] = { 0, 0, 0, 0 };
  285.  
  286.     glMaterialfv(GL_FRONT, GL_DIFFUSE, front_mat_diffuse);
  287.     glMaterialfv(GL_FRONT, GL_AMBIENT, front_mat_ambient);
  288.     glMaterialfv(GL_BACK, GL_DIFFUSE, back_mat_diffuse);
  289.     glMaterialfv(GL_BACK, GL_AMBIENT, back_mat_ambient);
  290. }
  291.  
  292. void surfacematerials(void)
  293. {
  294.     float front_mat_diffuse[] = { 0.2, 0.7, 0.4, 1.0 };
  295.     float front_mat_ambient[] = { 0.1, 0.1, 0.1, 1.0 };
  296.     float back_mat_diffuse[] = { 1.0, 1.0, 0.2, 1.0 };
  297.     float back_mat_ambient[] = { 0.1, 0.1, 0.1, 1.0 };
  298.  
  299.     glMaterialfv(GL_FRONT, GL_DIFFUSE, front_mat_diffuse);
  300.     glMaterialfv(GL_FRONT, GL_AMBIENT, front_mat_ambient);
  301.     glMaterialfv(GL_BACK, GL_DIFFUSE, back_mat_diffuse);
  302.     glMaterialfv(GL_BACK, GL_AMBIENT, back_mat_ambient);
  303. }
  304.  
  305. void init(int argc, char **argv, int fullscreen)
  306. {
  307.     int i;
  308.     float ambient[] = { 0.0, 0.0, 0.0, 1.0 };
  309.     float diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
  310.     float position[] = { 90.0, 90.0, -150.0, 0.0 };
  311.     float lmodel_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
  312.     float lmodel_twoside[] = { GL_TRUE };
  313.  
  314.     window = createwindow( argc, argv, fullscreen );
  315.     cx = glXCreateContext(dpy, vi, 0, GL_TRUE);
  316.     if (!glXMakeCurrent(dpy, window, cx)) {
  317.     fprintf(stderr, "Can't make window current to context\n");
  318.     exit(EXIT_FAILURE);
  319.     }
  320.     if (!getExtension("GL_EXT_polygon_offset")) {
  321.     fprintf(stderr, "Sorry GL_EXT_polygon_offset is not supported.\n");
  322.         exit(EXIT_FAILURE);
  323.     }
  324.     glLineWidth(2);
  325.     glMatrixMode(GL_PROJECTION);
  326.     glLoadIdentity();
  327.     gluPerspective( 40.0, 1.0, 2.0, 200.0 );
  328.     glMatrixMode(GL_MODELVIEW);
  329.     glLoadIdentity();
  330.  
  331.     glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
  332.     glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
  333.     glLightfv(GL_LIGHT0, GL_POSITION, position);
  334.     glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
  335.  
  336.     glEnable(GL_LIGHTING);
  337.     glEnable(GL_LIGHT0);
  338.     glEnable(GL_DEPTH_TEST);
  339.     glEnable(GL_AUTO_NORMAL);
  340.     glFrontFace(GL_CCW);
  341.  
  342.     glEnable( GL_MAP2_VERTEX_4 );
  343.     glClearColor(0.25, 0.25, 0.5, 0.0);
  344.  
  345. #ifdef GL_EXT_polygon_offset
  346.     glEnable(GL_POLYGON_OFFSET_EXT);
  347.     glPolygonOffsetEXT( scale, bias );
  348. #endif
  349.     nobj = gluNewNurbsRenderer();
  350.     gluNurbsProperty(nobj, GLU_SAMPLING_METHOD, GLU_DOMAIN_DISTANCE );
  351.  
  352.     surflist = glGenLists(1);
  353.     gridlist = glGenLists(1);
  354.     createlists();
  355. }
  356.  
  357. void drawmesh(void)
  358. {
  359.     int i, j;
  360.     float *p;
  361.  
  362.     int up2p = 4;
  363.     int uorder = 3, vorder = 3;
  364.     int nu = 4, nv = 4;
  365.     int vp2p = up2p * uorder * nu;
  366.  
  367.     for (j=0; j < nv; j++) {
  368.     for (i=0; i < nu; i++) {
  369.         p = torusbezierpts + (j * vp2p * vorder) + (i * up2p * uorder);
  370. #ifdef GL_EXT_polygon_offset
  371.         glPolygonOffsetEXT( scale, bias );
  372. #endif
  373.             glMap2f( GL_MAP2_VERTEX_4, 0.0, 1.0, up2p, 3, 0.0, 1.0, vp2p, 3,
  374.              (void*)p );
  375.         if (showsurf) {
  376.         surfacematerials();
  377.         glEvalMesh2( GL_FILL, 0, usegments, 0, vsegments );
  378.         }
  379.         if (showgrid) {
  380.                 gridmaterials();
  381.             glEvalMesh2( GL_LINE, 0, usegments, 0, vsegments );
  382.             }
  383.     }
  384.     }
  385. }
  386.  
  387. void redraw(void)
  388. {
  389.     static int i=0;
  390.     int dx, dy;
  391.     float v[3], n[3], rot[3];
  392.     float len, rlen, ang;
  393.     static GLuint vcount;
  394.  
  395.     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  396.     glColor3f( 1, 0, 0);
  397.  
  398.     if (tracking) {
  399.     dx = curx - startx;
  400.     dy = cury - starty;
  401.     } else {
  402.     dx = spindx;
  403.     dy = spindy;
  404.     }
  405.     if (dx || dy) {
  406.     dy = -dy;
  407.     v[0] = dx;
  408.     v[1] = dy;
  409.     v[2] = 0;
  410.  
  411.     len = length(v);
  412.     ang = -len / 600 * 360;
  413.     norm( v );
  414.     cross( v, z_axis, rot );
  415.  
  416.     /*
  417.         ** We concatenate the rotation onto the current modelview matrix and
  418.         ** read the matrix back, thus saving ourselves from writing our own
  419.     ** matrix manipulation routines.
  420.     ** This is certainly not recommended for programs that care
  421.     ** about performance or numerical stability :-)
  422.     */
  423.     glLoadIdentity();
  424.     glRotatef(ang, rot[0], rot[1], rot[2]);
  425.     glMultMatrixf(modelmatrix);
  426.     glGetFloatv(GL_MODELVIEW_MATRIX, modelmatrix);
  427.     }
  428.     glLoadIdentity();
  429.     glTranslatef( 0.0, 0.0, -10.0 );
  430.     glMultMatrixf(modelmatrix);
  431.     
  432.     if (useglunurbs) {
  433.     if (showsurf) glCallList(surflist);
  434.     if (showgrid) glCallList(gridlist);
  435.     } else {
  436.     glMapGrid2f( usegments, 0.0, 1.0, vsegments, 0.0, 1.0 );
  437.     drawmesh();
  438.     }
  439.  
  440.     glXSwapBuffers(dpy, window);
  441. }
  442.  
  443. static void usage(char *name, int exitStatus)
  444. {
  445.     fprintf(stderr, "usage: %s [-f (for full screen)] [-h(elp)]\n", name);
  446.     fprintf(stderr,
  447.             "\tInteractively, `h/?' keys provide description of interface\n");
  448.     exit(exitStatus);
  449. }
  450.  
  451. void
  452. main(int argc, char **argv)
  453. {
  454.     int i, ms, fullscreen = 0; 
  455.  
  456.     for (i=1; i<argc; i++) {
  457.     if (argv[i][0] == '-') {
  458.         switch (argv[i][1]) {
  459.           case 'f':
  460.         fullscreen = 1;
  461.         break;
  462.               case 'h':
  463.         usage(argv[0], EXIT_SUCCESS);
  464.           default:
  465.         usage(argv[0], EXIT_FAILURE);
  466.         }
  467.     } else {
  468.         usage(argv[0], EXIT_FAILURE);
  469.     }
  470.     }
  471.  
  472.     init(argc, argv, fullscreen);
  473.     eventloop();
  474.     glXMakeCurrent(dpy, None, NULL);
  475.     glXDestroyContext(dpy, cx);
  476.     XCloseDisplay(dpy);
  477. }
  478.  
  479. /****************************************************************************/
  480.  
  481. float circleknots[] = { 0.0, 0.0, 0.0, 0.25, 0.50, 0.50, 0.75, 1.0, 1.0, 1.0 };
  482.  
  483. void createlists(void)
  484. {
  485.     gluNurbsProperty(nobj, GLU_U_STEP, (usegments-1)*4 );
  486.     gluNurbsProperty(nobj, GLU_V_STEP, (vsegments-1)*4 );
  487.  
  488.     gluNurbsProperty(nobj, GLU_DISPLAY_MODE, GLU_FILL);
  489.     glNewList(surflist, GL_COMPILE);
  490.         surfacematerials();
  491.         gluBeginSurface(nobj);
  492.         gluNurbsSurface(nobj, 10, circleknots, 10, circleknots,
  493.                 4, 28, torusnurbpts, 3, 3, GL_MAP2_VERTEX_4);
  494.         gluEndSurface(nobj);
  495.     glEndList();
  496.  
  497.     gluNurbsProperty(nobj, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON);
  498.     glNewList(gridlist, GL_COMPILE);
  499.         gridmaterials();
  500.         gluBeginSurface(nobj);
  501.         gluNurbsSurface(nobj, 10, circleknots, 10, circleknots,
  502.                 4, 28, torusnurbpts, 3, 3, GL_MAP2_VERTEX_4);
  503.         gluEndSurface(nobj);
  504.     glEndList();
  505. }
  506.  
  507. /****************************************************************************/
  508.  
  509. /*
  510.  * Create an X window.
  511.  */
  512.  
  513. static Bool WaitForMapNotify(Display *d, XEvent *e, char *arg)
  514. {
  515.     if ((e->type == MapNotify) && (e->xmap.window == (Window)arg)) {
  516.     return GL_TRUE;
  517.     }
  518.     return GL_FALSE;
  519. }
  520.  
  521. Window createwindow(int argc, char **argv, Bool fullscreen)
  522. {
  523.     Window window;
  524.     XSetWindowAttributes swa;
  525.     unsigned int width, height;
  526.     XSizeHints sh;
  527.     XEvent event;
  528.     const char *extensions;
  529.     char title[100];
  530.     int attributes[] = {
  531. #ifdef GL_SGIS_multisample
  532.         GLX_SAMPLES_SGIS,
  533. #else
  534.         None,                   /* Note used - simplifies the code */
  535. #endif
  536.         0,
  537.         GLX_RGBA,
  538.         GLX_DOUBLEBUFFER,
  539.         GLX_RED_SIZE, 1,
  540.         GLX_GREEN_SIZE, 1,
  541.         GLX_BLUE_SIZE, 1,
  542.         GLX_DEPTH_SIZE, 1,
  543.         None,
  544.     };
  545.  
  546.     dpy = XOpenDisplay(0);
  547.     if (!dpy) {
  548.     fprintf(stderr, "Can't connect to display \"%s\"\n",
  549.         getenv("DISPLAY"));
  550.     exit(EXIT_FAILURE);
  551.     }
  552. #ifdef GL_SGIS_multisample
  553.     extensions = glXQueryExtensionsString(dpy, DefaultScreen(dpy));
  554.     hasMultisampling = extensions == NULL ||
  555.         strstr(extensions, "GLX_SGIS_multisample") == NULL;
  556. #else
  557.     hasMultisampling = GL_FALSE;
  558. #endif
  559.     if (hasMultisampling) {
  560.         int logMs;
  561.         /* Try to get the largest number of samples */
  562.         for (vi = NULL, logMs = 4; logMs && vi == NULL; logMs--) {
  563.             attributes[1] = logMs > 1 ? 1 << logMs : 0;
  564.             vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributes);
  565.         }
  566.         sprintf(title,"%s - %d samples", argv[0], attributes[1]);
  567.     } else {
  568.         vi = glXChooseVisual(dpy, DefaultScreen(dpy), &attributes[2]);
  569.         sprintf(title,"%s", argv[0]);
  570.     }
  571.     if (!vi) {
  572.         fprintf(stderr, "Cannot find visual on \"%s\"\n", getenv("DISPLAY"));
  573.         exit(EXIT_FAILURE);
  574.     }
  575.  
  576.     cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual,
  577.                AllocNone);
  578.     swa.background_pixel = 0;
  579.     swa.border_pixel = 0;
  580.     swa.colormap = cmap;
  581.     swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask |
  582.         KeyReleaseMask | ButtonPressMask | ButtonMotionMask | ButtonReleaseMask;
  583.  
  584.     if (fullscreen) {
  585.     width = DisplayWidth( dpy, 0 );
  586.     height = DisplayHeight( dpy, 0 );
  587.     sh.x = 0;
  588.     sh.y = 0;
  589.     } else {
  590.         width = winwidth;
  591.     height = winheight;
  592.     sh.x = 50;
  593.     sh.y = 50;
  594.     }
  595.     sh.flags = USPosition | PPosition;
  596.     window = XCreateWindow(dpy, RootWindow(dpy, vi->screen), sh.x, sh.y,
  597.                width, height,
  598.                0, vi->depth, InputOutput, vi->visual,
  599.                CWBorderPixel|CWColormap|CWEventMask|CWBackPixel,
  600.                &swa);
  601.     XSetStandardProperties(dpy, window, title, argv[0], None, argv, argc, &sh);
  602.     XSetWMColormapWindows(dpy, window, &window, 1);
  603.     if (fullscreen) {
  604.     /* turn off window decorations */
  605.     Atom hints_atom;
  606.     MotifWmHints hints;
  607.  
  608.     hints_atom = XInternAtom( dpy, "_MOTIF_WM_HINTS", 0 );
  609.     hints.flags = MWM_HINTS_DECORATIONS;
  610.     hints.decorations = 0;
  611.     XChangeProperty( dpy, window, hints_atom, hints_atom, 32,
  612.              PropModeReplace, (unsigned char*)&hints, 5 );
  613.     }
  614.     XMapWindow(dpy, window);
  615.     XIfEvent(dpy, &event, WaitForMapNotify, (char*)window);
  616.     return window;
  617. }
  618.  
  619. /*
  620.  * Control points of the torus in Bezier form.  Can be rendered
  621.  * using OpenGL evaluators.
  622.  */
  623. static GLfloat torusbezierpts[] = {
  624.      4.0, 0.0, 0.0, 4.0, 2.0, 0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0,
  625.          3.0, 0.0, 1.0, 2.0, 4.0, 0.0, 1.0, 2.0, 8.0, 0.0, 0.0, 4.0,
  626.          8.0, 0.0, 0.0, 4.0, 4.0, 0.0,-1.0, 2.0, 3.0, 0.0,-1.0, 2.0,
  627.          3.0, 0.0,-1.0, 2.0, 2.0, 0.0,-1.0, 2.0, 4.0, 0.0, 0.0, 4.0,
  628.          2.0,-2.0, 0.0, 2.0, 1.0,-1.0, 0.5, 1.0, 1.5,-1.5, 0.5, 1.0,
  629.          1.5,-1.5, 0.5, 1.0, 2.0,-2.0, 0.5, 1.0, 4.0,-4.0, 0.0, 2.0,
  630.          4.0,-4.0, 0.0, 2.0, 2.0,-2.0,-0.5, 1.0, 1.5,-1.5,-0.5, 1.0,
  631.          1.5,-1.5,-0.5, 1.0, 1.0,-1.0,-0.5, 1.0, 2.0,-2.0, 0.0, 2.0,
  632.          0.0,-2.0, 0.0, 2.0, 0.0,-1.0, 0.5, 1.0, 0.0,-1.5, 0.5, 1.0,
  633.          0.0,-1.5, 0.5, 1.0, 0.0,-2.0, 0.5, 1.0, 0.0,-4.0, 0.0, 2.0,
  634.          0.0,-4.0, 0.0, 2.0, 0.0,-2.0,-0.5, 1.0, 0.0,-1.5,-0.5, 1.0,
  635.          0.0,-1.5,-0.5, 1.0, 0.0,-1.0,-0.5, 1.0, 0.0,-2.0, 0.0, 2.0,
  636.          0.0,-2.0, 0.0, 2.0, 0.0,-1.0, 0.5, 1.0, 0.0,-1.5, 0.5, 1.0,
  637.          0.0,-1.5, 0.5, 1.0, 0.0,-2.0, 0.5, 1.0, 0.0,-4.0, 0.0, 2.0,
  638.          0.0,-4.0, 0.0, 2.0, 0.0,-2.0,-0.5, 1.0, 0.0,-1.5,-0.5, 1.0,
  639.          0.0,-1.5,-0.5, 1.0, 0.0,-1.0,-0.5, 1.0, 0.0,-2.0, 0.0, 2.0,
  640.         -2.0,-2.0, 0.0, 2.0,-1.0,-1.0, 0.5, 1.0,-1.5,-1.5, 0.5, 1.0,
  641.         -1.5,-1.5, 0.5, 1.0,-2.0,-2.0, 0.5, 1.0,-4.0,-4.0, 0.0, 2.0,
  642.         -4.0,-4.0, 0.0, 2.0,-2.0,-2.0,-0.5, 1.0,-1.5,-1.5,-0.5, 1.0,
  643.         -1.5,-1.5,-0.5, 1.0,-1.0,-1.0,-0.5, 1.0,-2.0,-2.0, 0.0, 2.0,
  644.         -4.0, 0.0, 0.0, 4.0,-2.0, 0.0, 1.0, 2.0,-3.0, 0.0, 1.0, 2.0,
  645.         -3.0, 0.0, 1.0, 2.0,-4.0, 0.0, 1.0, 2.0,-8.0, 0.0, 0.0, 4.0,
  646.         -8.0, 0.0, 0.0, 4.0,-4.0, 0.0,-1.0, 2.0,-3.0, 0.0,-1.0, 2.0,
  647.         -3.0, 0.0,-1.0, 2.0,-2.0, 0.0,-1.0, 2.0,-4.0, 0.0, 0.0, 4.0,
  648.         -4.0, 0.0, 0.0, 4.0,-2.0, 0.0, 1.0, 2.0,-3.0, 0.0, 1.0, 2.0,
  649.         -3.0, 0.0, 1.0, 2.0,-4.0, 0.0, 1.0, 2.0,-8.0, 0.0, 0.0, 4.0,
  650.         -8.0, 0.0, 0.0, 4.0,-4.0, 0.0,-1.0, 2.0,-3.0, 0.0,-1.0, 2.0,
  651.         -3.0, 0.0,-1.0, 2.0,-2.0, 0.0,-1.0, 2.0,-4.0, 0.0, 0.0, 4.0,
  652.         -2.0, 2.0, 0.0, 2.0,-1.0, 1.0, 0.5, 1.0,-1.5, 1.5, 0.5, 1.0,
  653.         -1.5, 1.5, 0.5, 1.0,-2.0, 2.0, 0.5, 1.0,-4.0, 4.0, 0.0, 2.0,
  654.         -4.0, 4.0, 0.0, 2.0,-2.0, 2.0,-0.5, 1.0,-1.5, 1.5,-0.5, 1.0,
  655.         -1.5, 1.5,-0.5, 1.0,-1.0, 1.0,-0.5, 1.0,-2.0, 2.0, 0.0, 2.0,
  656.          0.0, 2.0, 0.0, 2.0, 0.0, 1.0, 0.5, 1.0, 0.0, 1.5, 0.5, 1.0,
  657.          0.0, 1.5, 0.5, 1.0, 0.0, 2.0, 0.5, 1.0, 0.0, 4.0, 0.0, 2.0,
  658.          0.0, 4.0, 0.0, 2.0, 0.0, 2.0,-0.5, 1.0, 0.0, 1.5,-0.5, 1.0,
  659.          0.0, 1.5,-0.5, 1.0, 0.0, 1.0,-0.5, 1.0, 0.0, 2.0, 0.0, 2.0,
  660.          0.0, 2.0, 0.0, 2.0, 0.0, 1.0, 0.5, 1.0, 0.0, 1.5, 0.5, 1.0,
  661.          0.0, 1.5, 0.5, 1.0, 0.0, 2.0, 0.5, 1.0, 0.0, 4.0, 0.0, 2.0,
  662.          0.0, 4.0, 0.0, 2.0, 0.0, 2.0,-0.5, 1.0, 0.0, 1.5,-0.5, 1.0,
  663.          0.0, 1.5,-0.5, 1.0, 0.0, 1.0,-0.5, 1.0, 0.0, 2.0, 0.0, 2.0,
  664.          2.0, 2.0, 0.0, 2.0, 1.0, 1.0, 0.5, 1.0, 1.5, 1.5, 0.5, 1.0,
  665.          1.5, 1.5, 0.5, 1.0, 2.0, 2.0, 0.5, 1.0, 4.0, 4.0, 0.0, 2.0,
  666.          4.0, 4.0, 0.0, 2.0, 2.0, 2.0,-0.5, 1.0, 1.5, 1.5,-0.5, 1.0,
  667.          1.5, 1.5,-0.5, 1.0, 1.0, 1.0,-0.5, 1.0, 2.0, 2.0, 0.0, 2.0,
  668.          4.0, 0.0, 0.0, 4.0, 2.0, 0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0,
  669.          3.0, 0.0, 1.0, 2.0, 4.0, 0.0, 1.0, 2.0, 8.0, 0.0, 0.0, 4.0,
  670.          8.0, 0.0, 0.0, 4.0, 4.0, 0.0,-1.0, 2.0, 3.0, 0.0,-1.0, 2.0,
  671.          3.0, 0.0,-1.0, 2.0, 2.0, 0.0,-1.0, 2.0, 4.0, 0.0, 0.0, 4.0,
  672. };
  673.  
  674. /*
  675.  * Control points of a torus in NURBS form.  Can be rendered using
  676.  * the GLU NURBS routines.
  677.  */
  678. static GLfloat torusnurbpts[] = {
  679.          4.0, 0.0, 0.0, 4.0, 2.0, 0.0, 1.0, 2.0, 4.0, 0.0, 1.0, 2.0,
  680.          8.0, 0.0, 0.0, 4.0, 4.0, 0.0,-1.0, 2.0, 2.0, 0.0,-1.0, 2.0,
  681.          4.0, 0.0, 0.0, 4.0, 2.0,-2.0, 0.0, 2.0, 1.0,-1.0, 0.5, 1.0,
  682.          2.0,-2.0, 0.5, 1.0, 4.0,-4.0, 0.0, 2.0, 2.0,-2.0,-0.5, 1.0,
  683.          1.0,-1.0,-0.5, 1.0, 2.0,-2.0, 0.0, 2.0,-2.0,-2.0, 0.0, 2.0,
  684.         -1.0,-1.0, 0.5, 1.0,-2.0,-2.0, 0.5, 1.0,-4.0,-4.0, 0.0, 2.0,
  685.         -2.0,-2.0,-0.5, 1.0,-1.0,-1.0,-0.5, 1.0,-2.0,-2.0, 0.0, 2.0,
  686.         -4.0, 0.0, 0.0, 4.0,-2.0, 0.0, 1.0, 2.0,-4.0, 0.0, 1.0, 2.0,
  687.         -8.0, 0.0, 0.0, 4.0,-4.0, 0.0,-1.0, 2.0,-2.0, 0.0,-1.0, 2.0,
  688.         -4.0, 0.0, 0.0, 4.0,-2.0, 2.0, 0.0, 2.0,-1.0, 1.0, 0.5, 1.0,
  689.         -2.0, 2.0, 0.5, 1.0,-4.0, 4.0, 0.0, 2.0,-2.0, 2.0,-0.5, 1.0,
  690.         -1.0, 1.0,-0.5, 1.0,-2.0, 2.0, 0.0, 2.0, 2.0, 2.0, 0.0, 2.0,
  691.          1.0, 1.0, 0.5, 1.0, 2.0, 2.0, 0.5, 1.0, 4.0, 4.0, 0.0, 2.0,
  692.          2.0, 2.0,-0.5, 1.0, 1.0, 1.0,-0.5, 1.0, 2.0, 2.0, 0.0, 2.0,
  693.          4.0, 0.0, 0.0, 4.0, 2.0, 0.0, 1.0, 2.0, 4.0, 0.0, 1.0, 2.0,
  694.          8.0, 0.0, 0.0, 4.0, 4.0, 0.0,-1.0, 2.0, 2.0, 0.0,-1.0, 2.0,
  695.          4.0, 0.0, 0.0, 4.0,
  696. };
  697.